usingFlux, Distributionsstruct VarCoeffGARCH constant::Vector{Float32} net::Chain x0::Vector{Float32}endFlux.@functor VarCoeffGARCHVarCoeffGARCH(net::Chain) =VarCoeffGARCH([-9], net, [0.0])functiongarch_mean_ll(m::VarCoeffGARCH, y::Vector{Float32})::Float32 sigmas, _ =garch_forward(m,y) conditional_dists =Normal.(0, sigmas)returnmean(logpdf.(conditional_dists, y))end#Use functional implementation to calculate conditional stddev.#Then, we don't need to store stddev_t to calculate stddev_t+1#and thus avoid mutation, which doesn't work with Zygote#(could use Zygote.Buffer, but it's often discouraged)functiongarch_forward(m::VarCoeffGARCH, y::Vector{Float32}) sigma_1, params_1 =m(m.x0[1], sqrt(softplus(m.constant[1]))) sigma_rec, params_rec =garch_forward_recurse(m, sigma_1, y, 1) sigmas_result =vcat(sigma_1, sigma_rec) params_result =hcat(params_1, params_rec)return sigmas_result, params_resultendfunctiongarch_forward_recurse(m::VarCoeffGARCH, sigma_tm1::Float32, y::Vector{Float32}, t::Int64) sigma_t, params_t =m(y[t], sigma_tm1)if t==length(y)-1return sigma_t, params_tend sigma_rec, params_rec =garch_forward_recurse(m, sigma_t, y, t+1) sigmas_result =vcat(sigma_t, sigma_rec) params_result =hcat(params_t, params_rec)return sigmas_result, params_resultendfunction (m::VarCoeffGARCH)(y::Float32, sigma::Float32) input_vec =vcat(y, sigma) params = m.net(input_vec) params_stable =get_garch_stable_params(params) #to ensure stationarity of the resulting GARCH processreturnsqrt(softplus(m.constant[1]) +sum(input_vec.^2.* params_stable)), params_stableend#transform both parameters to be >0 each and their sum to be <1get_garch_stable_params(x::Vector{Float32}) =vcat(σ(x[1]), (1-σ(x[1]))*σ(x[2]))
get_garch_stable_params (generic function with 1 method)
usingKernelDensityvar_coef_ll =mean([log(pdf(kde(y_forecast_sample[t,:]),test[t])) for t in1:100])standard_ll =mean([log(pdf(kde(garch_forecast_sample[t,:]),test[t])) for t in1:100])println(var_coef_ll)println(standard_ll)